技巧20 使用ADD指令将文件注入镜像里

尽管用户可以使用 RUN 命令和一些基础的shell原语在Dockerfile里添加文件,但是这很快就会变得无法管理。 ADD 命令加入Dockerfile的命令列表里正是为了满足将大量文件有条不紊地放入一个镜像的需求。

问题

想要以一种简洁的方式下载并解压一个压缩包到镜像里。

解决方案

打包并压缩目标文件,然后在Dockerfile里使用 ADD 指令。

通过 mkdir add_example && cd add_example 来为这次Docker构建创造一个全新的环境。随后检索一个压缩包,并给它指定一个名字作为后续引用的标识,如代码清单4-1所示。

代码清单4-1 下载一个TAR文件

$ curl \
https://www.flamingspork.com/projects/libeatmydata/
➥ libeatmydata-105.tar.gz > my.tar.gz

在这种情况下,我们使用的是通过另外一个技巧得到的TAR文件,但是其实它可以是你喜欢的任意一个压缩包,如代码清单4-2所示。

代码清单4-2 添加一个TAR文件到镜像里

FROM debian
RUN mkdir -p /opt/libeatmydata
ADD my.tar.gz /opt/libeatmydata/
RUN ls -lRt /opt/libeatmydata

通过 docker build --no-cache .来构建这个Dockerfile,它的输出内容应该与代码清单4-3所示内容类似。

代码清单4-3 带有TAR文件的镜像构建

$ docker build --no-cache .
Sending build context to Docker daemon 422.9 kB
Sending build context to Docker daemon
Step 0 : FROM debian
 ---> c90d655b99b2
Step 1 : RUN mkdir -p /opt/libeatmydata
 ---> Running in fe04bac7df74
 ---> c0ab8c88bb46
Removing intermediate container fe04bac7df74
Step 2 : ADD my.tar.gz /opt/libeatmydata/
 ---> 06dcd7a88eb7
Removing intermediate container 3f093a1f9e33
Step 3 : RUN ls -lRt /opt/libeatmydata
 ---> Running in e3283848ad65
/opt/libeatmydata:
total 4
drwxr-xr-x 7 1000 1000 4096 Oct 29 23:02 libeatmydata-105
/opt/libeatmydata/libeatmydata-105:
total 880
drwxr-xr-x 2 1000 1000   4096 Oct 29 23:02 config
drwxr-xr-x 3 1000 1000   4096 Oct 29 23:02 debian
drwxr-xr-x 2 1000 1000   4096 Oct 29 23:02 docs
drwxr-xr-x 3 1000 1000   4096 Oct 29 23:02 libeatmydata
drwxr-xr-x 2 1000 1000   4096 Oct 29 23:02 m4
-rw-r--r-- 1 1000 1000   9803 Oct 29 23:01 config.h.in
[............]
-rw-r--r-- 1 1000 1000   1824 Jun 18  2012 pandora_have_better_malloc.m4
-rw-r--r-- 1 1000 1000    742 Jun 18  2012 pandora_header_assert.m4
-rw-r--r-- 1 1000 1000    431 Jun 18  2012 pandora_version.m4
 ---> 2ee9b4c8059f
Removing intermediate container e3283848ad65
Successfully built 2ee9b4c8059f

从输出中可以看到,压缩包被Docker守护进程解压到了目标目录(所有文件的扩展输出已被省略)。Docker支持解压绝大多数标准类型的压缩文件(.gz、.bz2、.xz、.tar)。

值得留意的是,尽管用户可以从指定的URL下载压缩包,但是只有当它们被存储在本地文件系统时才会被自动解压。这一点可能会导致混淆。

如果使用代码清单4-4所示的Dockerfile重复上述过程,用户将会发现文件会被下载下来但是没有被解压。

代码清单4-4 从指定的URL直接添加TAR文件

FROM debian
RUN mkdir -p /opt/libeatmydata
ADD \  ⇽--- 根据指定的URL从网上检索该文件
 https://www.flamingspork.com/projects/libeatmydata/libeatmydata-105.tar.gz \
/opt/libeatmydata/  ⇽--- 目标目录通过目录名和尾部斜杠表示。如果没有尾部斜杠,Docker在构建时则会将参数视为下载文件的文件名
RUN ls -lRt /opt/libeatmydata

下面是构建的输出结果:

Sending build context to Docker daemon 422.9 kB
Sending build context to Docker daemon
Step 0 : FROM debian
 ---> c90d655b99b2
Step 1 : RUN mkdir -p /opt/libeatmydata
 ---> Running in 6ac454c52962
 ---> bdd948e413c1
Removing intermediate container 6ac454c52962
Step 2 : ADD \
https://www.flamingspork.com/projects/libeatmydata/libeatmydata-105.tar.gz/opt/libeatmydata/
Downloading [==================================================>] \
419.4 kB/419.4 kB
 ---> 9d8758e90b64
Removing intermediate container 02545663f13f
Step 3 : RUN ls -lRt /opt/libeatmydata
 ---> Running in a947eaa04b8e
/opt/libeatmydata:
total 412
-rw------- 1 root root 419427 Jan  1   1970 \
libeatmydata-105.tar.gz  ⇽---  libeatmydata-105.tar.gz 文件被下载并存放到/opt/libeatmydata目录,但是没有被解压
 ---> f18886c2418a
Removing intermediate container a947eaa04b8e
Successfully built f18886c2418a

值得一提的是,在前面那个Dockerfile里, ADD 那行如果不带尾部斜杠,Docker守护进程在执行构建时会将文件下载下来并以该文件名保存。带上尾部斜杠意味着该文件应该被下载并存放到指定的目录下。

所有新的文件和目录都归属于root用户(或是容器里组或用户ID为0的那个用户)。

文件名里带有空格

如果指定的文件名里带有空格,用户将需要在 ADD (或 COPY )时带上引号的形式

ADD "space file.txt" "/tmp/space file.txt"

讨论

ADD Dockerfile指令非常强大,它提供了许多各式各样的功能可供利用。如果用户想要编写多个Dockerfile(在阅读本书的过程中你可能会这样做),那么Dockerfile指令的官方文档值得好好读一读——并不多(在编写本书时官方文档里只列出了18条指令),而且用户经常用到的只是其中的一小部分。

人们常问的一个问题是如何添加一个压缩文件,但不对其进行解压。为此,用户应该使用的是 COPY 命令,该命令看上去和 ADD 命令完全相同,但是它不会解压任何文件,也不支持通过互联网下载文件。

results matching ""

    No results matching ""